package com.wg.elasticsearch.service;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.wg.elasticsearch.constant.ElasticsearchConstants;
import com.wg.elasticsearch.model.ShowContent;
import com.wg.elasticsearch.param.ContentParam;
import com.wg.elasticsearch.result.ResultSupport;
import com.wg.elasticsearch.util.DateUtil;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.*;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.IndicesExists;
import io.searchbox.indices.mapping.PutMapping;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by mc on 18/6/22.
 */
@Service
public class ElasticsearchServiceImpl implements ElasticsearchService {

    @Autowired
    private JestClient jestClient;

    /**
     * 创建索引
     * @param indexName
     * @return
     * 如果不存在直接创建，存在就不创建
     */
    @Override
    public boolean createIndex(String indexName) {
        try {
            IndicesExists indicesExists = new IndicesExists.Builder(ElasticsearchConstants.ES_JEST_INDEX_NAME).build();
            JestResult result = jestClient.execute(indicesExists);
            boolean flag = result.isSucceeded();
            if(!flag) {
                JestResult  jr = jestClient.execute(new CreateIndex.Builder(ElasticsearchConstants.ES_JEST_INDEX_NAME).build());
                return jr.isSucceeded();
            }
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除索引
     * @param indexName
     * @return
     */
    @Override
    public boolean delete(String indexName) {
        try {
            JestResult jr  = jestClient.execute(new DeleteIndex.Builder(indexName).build());
            return jr.isSucceeded();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 创建映射推送数据
     * @param indexName
     * @param typeName
     * @param source
     * @param list<Object>
     * @return
     * @throws Exception
     */
    @Override
    public boolean createMappingPushData(String indexName, String typeName, String source, List<Object> list) {
        boolean flag = true;
        try {
            boolean result = this.createIndexMapping(indexName, typeName, source);
            if(result){
                flag = this.insert(indexName, typeName, list);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * Put映射
     * @param indexName
     * @param typeName
     * @param source
     * @return
     * @throws Exception
     */
    @Override
    public boolean createIndexMapping(String indexName, String typeName, String source) {
        try {
            PutMapping putMapping = new PutMapping.Builder(indexName, typeName, source).build();
            JestResult jr = jestClient.execute(putMapping);
            return jr.isSucceeded();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 索引文档
     * @param indexName
     * @param typeName
     * @param objs
     * @return
     * @throws Exception
     */
    @Override
    public boolean insert(String indexName, String typeName, List<Object> objs) {
        try {
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);
            for (Object obj : objs) {
                Index index = new Index.Builder(obj).build();
                bulk.addAction(index);
            }
            BulkResult br = jestClient.execute(bulk.build());
            return br.isSucceeded();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }


     /**
     * 创建ES文档字段
     * @return
     */
     @Override
    public String getSourceName(){
        String source = "{\"" + ElasticsearchConstants.ES_JEST_TYPE_NAME + "\":{\"properties\":{"
                + "\"id\":{\"type\":\"integer\"}"
                + ",\"showContent\":{\"type\":\"string\",\"index\":\"analyzed\"}"
                + ",\"showTag\":{\"type\":\"string\",\"index\":\"not_analyzed\"}"
                + ",\"userId\":{\"type\":\"string\",\"index\":\"not_analyzed\"}"
                + ",\"title\":{\"type\":\"string\",\"index\":\"not_analyzed\"}"
                + ",\"updated\":{\"type\":\"string\",\"index\":\"not_analyzed\"}"
                + ",\"created\":{\"type\":\"string\",\"index\":\"not_analyzed\"}"
                + ",\"deleted\":{\"type\":\"string\",\"index\":\"not_analyzed\"}"
                + "}}}";
        return source;
    }

    /**
     * 获取es最大更新时间
     * @return
     */
    @Override
    public String getMaxUpdateTime() {
        try {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.sort("updated", SortOrder.DESC);
            searchSourceBuilder.query(boolQueryBuilder);
            Search search = new Search.Builder(searchSourceBuilder.toString())
                    .addIndex(ElasticsearchConstants.ES_JEST_INDEX_NAME)
                    .addType(ElasticsearchConstants.ES_JEST_TYPE_NAME).build();
            JestResult jestResult = jestClient.execute(search);
            List<ShowContent> showContents = jestResult.getSourceAsObjectList(ShowContent.class);
            if(showContents != null && showContents.size() > 0){
                return DateUtil.getNowDate(showContents.get(0).getUpdated());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return String.valueOf(new Date());
    }

    @Override
    public boolean update(String indexName, String typeName, List<ShowContent> objs) {
        try {
            Map<String,Object> map = new HashMap();
            Map<String,Object> mapDoc = new HashMap();
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);
            for (ShowContent showContent : objs) {
                map.put("deleted", showContent.getDeleted());
                map.put("showTag", showContent.getShowTag());
                map.put("showContent", showContent.getShowContent());
                map.put("userId", showContent.getUserId());
                map.put("title", showContent.getTitle());
                map.put("updated", showContent.getUpdated());
                map.put("created", showContent.getCreated());
                map.put("deleted", showContent.getDeleted());
                mapDoc.put("doc",map);
                String filedName = JSONObject.toJSONString(mapDoc);
                Update update = new Update.Builder(filedName).id(showContent.getId().toString()).build();
                bulk.addAction(update);
            }
            BulkResult  br = jestClient.execute(bulk.build());
            return br.isSucceeded();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取数据
     * @param indexName
     * @param typeName
     * @param id
     * @return
     */
    @Override
    public ShowContent get(String indexName, String typeName, String id) {
        try {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            TermsQueryBuilder searchParam2 = QueryBuilders.termsQuery("id", id);
            boolQueryBuilder.must(searchParam2);
            searchSourceBuilder.query(boolQueryBuilder);
            Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(ElasticsearchConstants.ES_JEST_INDEX_NAME).addType(ElasticsearchConstants.ES_JEST_TYPE_NAME).build();
            JestResult jestResult = jestClient.execute(search);
            List<ShowContent> showContents = jestResult.getSourceAsObjectList(ShowContent.class);
            if(showContents.size() > 0){
                return showContents.get(0);
            }else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public ResultSupport<List<ShowContent>> search(ContentParam param) {
        List<ShowContent> showContents = Lists.newArrayList();
        try {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(param.getPageSize());
            searchSourceBuilder.from((param.getPageNum() - 1) * param.getPageSize());
            boolQueryBuilder = getSearchCondition(param, boolQueryBuilder);
            searchSourceBuilder.query(boolQueryBuilder);
            Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(ElasticsearchConstants.ES_JEST_INDEX_NAME).addType(ElasticsearchConstants.ES_JEST_TYPE_NAME).build();
            JestResult jestResult = jestClient.execute(search);
            showContents = jestResult.getSourceAsObjectList(ShowContent.class);

            BoolQueryBuilder boolQueryBuilders = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilders = new SearchSourceBuilder();
            searchSourceBuilders.sort("userId", SortOrder.DESC);
            boolQueryBuilders = getSearchCondition(param, boolQueryBuilders);
            searchSourceBuilders.query(boolQueryBuilders);
            Search searchs = new Search.Builder(searchSourceBuilders.toString()).addIndex(ElasticsearchConstants.ES_JEST_INDEX_NAME).addType(ElasticsearchConstants.ES_JEST_TYPE_NAME).build();
            Long totalCount = jestClient.execute(searchs).getTotal();
            return ResultSupport.successPage(showContents, totalCount);
        } catch (IOException e) {
            e.printStackTrace();
            return ResultSupport.failure(e.getMessage());
        }
    }

    /**
     * 搜索条件
     * @param param
     * @param boolQueryBuilder
     * @return
     */
    public BoolQueryBuilder getSearchCondition(ContentParam param, BoolQueryBuilder boolQueryBuilder){
        if(StringUtils.isNotBlank(param.getShowContent())){
            MatchPhraseQueryBuilder searchParam1 = QueryBuilders.matchPhraseQuery("showContent", param.getShowContent());
            boolQueryBuilder.must(searchParam1);
        }
        return boolQueryBuilder;
    }

}
